package main

import (
	"fmt"
	"regexp"
	"strings"
	"sync"
)

// Node 节点定义
type Node struct {
	value int
	tag   string
	level int
	// 暂时先增加tag标签，其他属性后加
}

// Graph 图表描述
type Graph struct {
	nodes []*Node          // 节点集
	edges map[Node][]*Node // 邻接表表示的无向图
	lock  sync.RWMutex     // 保证线程安全
}

// AddNode 增加节点
func (g *Graph) AddNode(n *Node) {
	g.lock.Lock()
	defer g.lock.Unlock()
	g.nodes = append(g.nodes, n)
}

// AddEdge 增加边
func (g *Graph) AddEdge(u, v *Node) {
	g.lock.Lock()
	defer g.lock.Unlock()
	// 首次建立图
	if g.edges == nil {
		g.edges = make(map[Node][]*Node)
	}
	g.edges[*u] = append(g.edges[*u], v) // 建立 u->v 的边
	//g.edges[*v] = append(g.edges[*v], u) // 由于是无向图，同时存在 v->u 的边
}

// TagString 返回节点tag值
func (n *Node) TagString() string {
	// 返回节点对应属性string
	return fmt.Sprintf("%v", n.tag)
}

// ValueString 返回节点value值
func (n *Node) ValueString() string {
	// 返回节点对应属性string
	return fmt.Sprintf("%v", n.value)
}

// MakeTagLeft 格式化标签对1
func MakeTagLeft(tagName string) string {
	return "<" + tagName + ">"
}

// MakeTagRight 格式化标签对2
func MakeTagRight(tagName string) string {
	return "</" + tagName + ">"
}

// MakeTagCount 生成制表符
func MakeTagCount(nodeLength int) string {
	var tabCount = ""
	for i := 0; i < nodeLength-1; i++ {
		tabCount += "\t"
	}
	return tabCount
}

// ModifyTags 根据图信息生成代码
func (g *Graph) ModifyTags() string {
	g.lock.RLock()
	defer g.lock.RUnlock()
	// 因为这个图并不是描述一个封闭图，而是存在父子节点关系，
	// 根据一开始给的图结构认为，只需要确定父节点位置，根据节点的长度关系，就能确定上下级，
	// 但是，如果出现3层以上的嵌套，这种方法不适用，在优化后，使用多层嵌套，但新问题出现，相同的标签会导致生成混乱，
	// 现需要解决，确定相同层数当中，相同标签的区别
	// todo 相同的标签会导致生成结构混乱
	// parentNode 存放父节点
	var parentNode = make(map[int]string)
	// parentNode 存放所有子节点tag
	var childrenNodeArr []string
	// maps 根据所有节点值来存放对应的生成代码后的空间，因为对应节点的value唯一因此，
	// 因此可以根据value==1来确定父节点的代码段
	var maps = make(map[int]string)
	// parentStr 根据maps取出来的代码段
	var parentStr string
	// childrenArr 根据maps取出来的所有代码切片
	var childrenArr []string

	for _, iNode := range g.nodes {
		nexts := g.edges[*iNode]
		// 因为是树形图，因此没有添加反向图信息，因此，当节点的长度信息为0，
		// 那么说明该节点为末端节点，
		// 判断节点数不为0的节点，获取相关的节点确认信息
		if len(nexts) != 0 {
			// 获取父节点nodes.value = 1的标签
			if iNode.value == 1 {
				parentNode[iNode.value] = iNode.tag
			}
			if iNode.value != 1 {
				childrenNodeArr = append(childrenNodeArr, iNode.tag)
			}
		}
		fmt.Println("----------------parentNode===>", parentNode)
		// 做同样的上述循环，将所有长度不为0的节点进行代码化
		if len(nexts) != 0 {
			var temp string
			// 拿到所有的节点
			temp += MakeTagLeft(iNode.TagString()) // <div>"<" +  + ">"
			// 拿到所有节点指向的值，这个边描述里存的是map
			//nexts := g.edges[*iNode]
			for _, next := range nexts {
				temp += "\n" + MakeTagCount(next.level) + MakeTagLeft(next.TagString()) + MakeTagRight(next.TagString()) //<from></from><button></button><Cmp_Logo></Cmp_Logo> "<" +  + ">""</" + + ">"
			}
			temp += "\n" + MakeTagCount(iNode.level) + MakeTagRight(iNode.TagString()) //</div> "</" + iNode.TagString() + ">"
			maps[iNode.value] = temp
			//}
		}
	}

	//fmt.Println("----------------maps===>", maps)
	fmt.Println("----------------childrenNodeArr===>", childrenNodeArr)
	// 取出父节点与所有子节点
	for k, v := range maps {
		if k == 1 {
			parentStr = v
		}
		if k != 1 {
			childrenArr = append(childrenArr, v)
		}
	}
	// 循环所有子节点，将父节点的tag替换
	fmt.Println("----------------par====>\n", parentStr)
	//fmt.Println("----------------childrenArr===>\n", childrenArr)
	for _, v := range childrenArr {
		for _, childTag := range childrenNodeArr {
			if strings.Contains(parentStr, MakeTagLeft(childTag)+MakeTagRight(childTag)) {
				// 判断是否存在此标签在一层的循环中，完成后更新父层字符串，跳出循环，进入下一次children代码替换
				//regTarget := regexp.MustCompile(`\<from>\</from>`)
				regTarget := regexp.MustCompile(MakeTagLeft(childTag) + MakeTagRight(childTag)) //`\<` + childTag + `>\</` + childTag + `>`
				//fmt.Println("----------------更改后===>\n", regTarget.ReplaceAllString(parentStr, v))
				parentStr = regTarget.ReplaceAllString(parentStr, v)
				break
			}

		}

	}

	//fmt.Println("----------------par====>\n", parentStr)
	//fmt.Println("chi====>", childrenArr)
	return parentStr
}

// PrintString 输出图关系
func (g *Graph) PrintString() {
	g.lock.RLock()
	defer g.lock.RUnlock()
	str := ""
	for _, iNode := range g.nodes {
		nexts := g.edges[*iNode]
		if len(nexts) != 0 {
			str += iNode.TagString() + " -> "
			for _, next := range nexts {
				str += next.TagString() + " "
			}
			str += "\n"
		}
	}
	fmt.Println(str)
}

func main() {
	g := Graph{}
	// 子节点长度为3的情况
	var div = Node{1, "div1", 1}
	var from = Node{2, "from", 2}
	var div2 = Node{3, "div2", 2}
	var clogo = Node{4, "Cmp_Logo", 2}
	var input1 = Node{5, "input", 3}
	var input2 = Node{6, "input", 3}
	var div3 = Node{7, "div3", 3}
	var button = Node{8, "button", 4}
	var span = Node{9, "span", 5}
	/*var table = Node{10, "table", 5}
	var tr = Node{9, "tr", 5}
	var td = Node{9, "td", 5}*/

	g.AddNode(&div)
	g.AddNode(&from)
	g.AddNode(&div2)
	g.AddNode(&clogo)
	g.AddNode(&input1)
	g.AddNode(&input2)
	g.AddNode(&div3)
	g.AddNode(&button)
	g.AddNode(&span)
	/*	g.AddNode(&table)
		g.AddNode(&tr)
		g.AddNode(&td)*/

	g.AddEdge(&div, &from)
	g.AddEdge(&div, &div2)
	g.AddEdge(&div, &clogo)
	g.AddEdge(&from, &input1)
	g.AddEdge(&from, &input2)
	g.AddEdge(&div2, &div3)
	g.AddEdge(&div3, &button)
	g.AddEdge(&button, &span)
	/*var div = Node{1, "div",1}
	var from = Node{2, "from",2}
	var button = Node{3, "button",2}
	var clogo = Node{4, "Cmp_Logo",2}
	var input1 = Node{5, "input",3}
	var input2 = Node{6, "input",3}

	g.AddNode(&div)
	g.AddNode(&from)
	g.AddNode(&button)
	g.AddNode(&clogo)
	g.AddNode(&input1)
	g.AddNode(&input2)

	g.AddEdge(&div, &from)
	g.AddEdge(&div, &button)
	g.AddEdge(&div, &clogo)
	g.AddEdge(&from, &input1)
	g.AddEdge(&from, &input2)*/
	fmt.Println("所有节点信息")
	for _, v := range g.nodes {
		fmt.Println(*v)
	}
	fmt.Println(g.edges)
	for _, v := range g.edges {
		for _, vv := range v {
			fmt.Println(vv)
		}
	}
	g.PrintString()
	var code = g.ModifyTags()
	fmt.Println()
	fmt.Println("返回结果====>\n", code)
	//fmt.Println(g.edges)

	/*str := "<div>\n\t<form>\n\t\t<input></input>\n\t\t<input></input>\n\t</form>\n\t<button></button>\n\t<Cmp_Logo></Cmp_Logo>\n</div>"
	fmt.Println(str)*/
}
